import { type FC, useCallback, useEffect, useRef } from "react";
import { Steps, Modal, message } from "antd";
import { initArticle } from "@/store/art-edit-store";
import { type LoaderFunctionArgs, useBeforeUnload, useBlocker, defer } from "react-router-dom";
import { stepItems } from "./article-add";
import useArtEditStore, { selectCurrent, resetCurrent, updateCurrent } from "@/store/art-edit-store";
import { ArticleSteps } from "@/store/art-add-store";
import { getCateListApi } from "@/api/cate-api";
import { putArticleApi } from "@/api/article-api";
import { to } from "await-to-js";
import EditBase from "@/components/article-edit/art-base";
import EditCover from "@/components/article-edit/art-cover";
import EditContent from "@/components/article-edit/art-content";
import EditResult from "@/components/article-edit/art-result";

const ArticleEdit: FC = () => {
  const current = useArtEditStore(selectCurrent);

  const blocker = useBlocker(({ currentLocation, nextLocation }) => {
    // 如果 return 的值为 true，则需要在导航之前，弹框询问用户是否确认离开
    // 如果 return 的值为 false，则在导航离开的时候，不需要进行弹框的确认，用户可以直接离开
    return currentLocation !== nextLocation && current !== ArticleSteps.done;
  });

  const modalRef = useRef<ReturnType<typeof Modal.confirm> | null>();

  useEffect(() => {
    // 1. 判断 blocker.state 是否等于 blocked
    if (blocker.state === "blocked") {
      if (modalRef.current) return;
      // 2. 需要展示确认的弹框
      modalRef.current = Modal.confirm({
        title: "温馨提示",
        content: "您所做的更改将会丢失，是否确认离开当前页面？",
        okText: "确认",
        cancelText: "取消",
        onOk() {
          // 允许离开
          blocker.proceed();
        },
        onCancel() {
          // 阻止离开
          blocker.reset();
          modalRef.current = null;
        },
      });
    }
  }, [blocker.state, blocker]);

  useBeforeUnload(
    useCallback((e) => {
      // 进行刷新的阻止
      e.preventDefault();
    }, [])
  );

  return (
    <div>
      {/* 步骤条 */}
      <Steps size="small" current={current} items={stepItems} />
      {/* 步骤条对应的组件 */}
      <div style={{ marginTop: "20px" }}>
        {current === ArticleSteps.base && <EditBase />}
        {current === ArticleSteps.cover && <EditCover />}
        {current === ArticleSteps.content && <EditContent />}
        {current === ArticleSteps.done && <EditResult />}
      </div>
    </div>
  );
};

export default ArticleEdit;

export const loader = async ({ params }: LoaderFunctionArgs) => {
  // 回显文章的数据
  const flag = initArticle(params.id!);
  // 请求文章分类的数据
  const cates = getCateListApi();

  // 重置 current 值
  resetCurrent();

  // 1. 方案1：把多个 Promise 封装到 Promise.all([]) 的数组中，统一返回给组件使用
  // 1. 方案2：把多个 Promise 封装到 defer 对象的多个属性中，这样，在组件中，可以只使用 Await 组件，等待自己需要的数据
  return defer({ cates, flag });
};

export const action = async () => {
  // 1. 拿到全局 Store 中存储的文章信息
  // 2. 需要对文章的信息进行梳理，得到一个 FormData 对象
  // 3. 调用接口
  const article = useArtEditStore.getState().article;

  const keys = ["id", "title", "cate_id", "content", "state", "cover_img"];

  // 需要把对象格式的请求体数据，转为 FormData 格式的请求体
  const fd = new FormData();
  keys.forEach((key) => {
    fd.append(key, article[key]);
  });

  const [err] = await to(putArticleApi(fd));
  if (err) return null;

  message.success("修改成功！");
  // 修改文章成功
  updateCurrent();
  // clearArticle();
  return null;
};
